package com.gokzzz.quartz;

import com.gokzzz.entity.SysQuartzJob;
import com.gokzzz.entity.SysQuartzLog;
import com.gokzzz.service.ISysQuartzLogService;
import com.gokzzz.util.SpringContextHolder;
import com.gokzzz.util.ThrowableUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.quartz.QuartzJobBean;

import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author ganfujia
 * @date 2022/4/21 13:29
 */
@Async
@Slf4j
public class ExecutionJob extends QuartzJobBean {

    /**
     * 线程池的核心线程数
     */
    private static final int CORE_POOL_SIZE = 1;
    /**
     * 能容纳的最大线程数
     */
    private static final int MAXIMUM_POOL_SIZE = 3;
    /**
     * 空闲线程的存活时间
     */
    private static final long KEEP_ALIVE_TIME = 60L;
    /**
     * 存活的时间单位
     */
    private static final TimeUnit TIME_UNIT = TimeUnit.SECONDS;
    /**
     * 存放提交但未执行的任务
     */
    private static final BlockingQueue<Runnable> WORK_QUEUE = new LinkedBlockingQueue<>(5);
    /**
     * 创建线程工厂
     */
    private static final ThreadFactory THREAD_FACTORY = Executors.defaultThreadFactory();
    /**
     * 等待队列满后的拒绝策略
     */
    private static final ThreadPoolExecutor.AbortPolicy HANDLER = new ThreadPoolExecutor.AbortPolicy();

    @Override
    protected void executeInternal(JobExecutionContext context) {
        ISysQuartzLogService sysQuartzLogService = SpringContextHolder.getBean(ISysQuartzLogService.class);
        // 手动创建单个线程
        ExecutorService executor = new ThreadPoolExecutor(
                CORE_POOL_SIZE,
                MAXIMUM_POOL_SIZE,
                KEEP_ALIVE_TIME,
                TIME_UNIT,
                WORK_QUEUE,
                THREAD_FACTORY,
                HANDLER
        );
        // 获取任务信息
        SysQuartzJob sysQuartzJob = (SysQuartzJob) context.getMergedJobDataMap().get(SysQuartzJob.JOB_KEY);
        long startTime = System.currentTimeMillis();
        SysQuartzLog sysQuartzLog = new SysQuartzLog();
        BeanUtils.copyProperties(sysQuartzJob, sysQuartzLog);
        sysQuartzLog.setCreateTime(new Date());
        try {
            QuartzRunnable task = new QuartzRunnable(sysQuartzJob.getBeanName(), sysQuartzJob.getMethodName(),
                    sysQuartzJob.getParams());
            executor.submit(task);
//            Future<?> future =
//            future.get();
            long times = System.currentTimeMillis() - startTime;
            sysQuartzLog.setTime(times);
            sysQuartzLog.setSuccess(true);
            log.info(">> 执行任务成功,任务名称为：{},耗时：{}ms <<", context.getJobDetail().getKey().getName(), times);
        } catch (Exception e) {
            long times = System.currentTimeMillis() - startTime;
            sysQuartzLog.setTime(times);
            sysQuartzLog.setSuccess(false);
            sysQuartzLog.setExceptionDetail(ThrowableUtil.getStackTraceByPn(e, "com.gokzzz"));
            log.error(">> 执行任务失败,任务名称为：{} <<",context.getJobDetail().getKey().getName(), e);
        } finally {
            sysQuartzLogService.save(sysQuartzLog);
            executor.shutdown();
        }
    }
}
